{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "feature_columns.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.5"
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rNdWfPXCjTjY"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "I1dUQ0GejU8N",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "c05P9g5WjizZ"
      },
      "source": [
        "# 構造化されたデータの分類"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "zofH_gCzgplN"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/structured_data/feature_columns\">\n",
        "    <img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />\n",
        "    View on TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ja/tutorials/structured_data/feature_columns.ipynb\">\n",
        "    <img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />\n",
        "    Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ja/tutorials/structured_data/feature_columns.ipynb\">\n",
        "    <img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />\n",
        "    View source on GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lrFrIDaEZAjE",
        "colab_type": "text"
      },
      "source": [
        "Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳は**ベストエフォート**であるため、この翻訳が正確であることや[英語の公式ドキュメント](https://www.tensorflow.org/?hl=en)の 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリ[tensorflow/docs](https://github.com/tensorflow/docs)にプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [docs-ja@tensorflow.org メーリングリスト](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ja)にご連絡ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "K1y4OHpGgss7"
      },
      "source": [
        "このチュートリアルでは、（例えばCSVファイルに保存された表形式データのような）構造化されたデータをどうやって分類するかを示します。ここでは、モデルの定義に[Keras](https://www.tensorflow.org/guide/keras)を、[feature columns](https://www.tensorflow.org/guide/feature_columns)をCSVファイルの列をモデルを訓練するための特徴量にマッピングするための橋渡し役として使用します。このチュートリアルには、下記のことを行うコードすべてが含まれています。\n",
        "\n",
        "* [Pandas](https://pandas.pydata.org/)を使用したCSVファイルの読み込み\n",
        "* [tf.data](https://www.tensorflow.org/guide/datasets)を使用して行データをシャッフルし、バッチ化するための入力パイプライン構築\n",
        "* feature columnsを使ったCSVの列のモデル訓練用の特徴量へのマッピング\n",
        "* Kerasを使ったモデルの構築と、訓練及び評価\n",
        "\n",
        "## データセット\n",
        "\n",
        "ここでは、Cleveland Clinic Foundation for Heart Diseaseが提供している小さな[データセット](https://archive.ics.uci.edu/ml/datasets/heart+Disease)を使用します。このCSVファイルには数百行が含まれています。行が患者を、列がその属性を表します。この情報を使用して、患者が心臓疾患を持っているかを予測します。このデータセットの場合には二値分類タスクとなります。\n",
        "\n",
        "下記はこのデータセットの[說明](https://archive.ics.uci.edu/ml/machine-learning-databases/heart-disease/heart-disease.names)です。数値列とカテゴリー列があることに注目してください。\n",
        "\n",
        ">列| 說明| 特徴量の型 | データ型\n",
        ">------------|--------------------|----------------------|-----------------\n",
        ">Age | 年齢 | 数値型 | 整数\n",
        ">Sex | (1 = 男性; 0 = 女性) | カテゴリー型 | 整数\n",
        ">CP | 胸痛のタイプ (0, 1, 2, 3, 4) | カテゴリー型 | 整数\n",
        ">Trestbpd | 安静時血圧 (単位：mm Hg 入院時) | 数値型 | 整数\n",
        ">Chol | 血清コレステロール 単位：mg/dl | 数値型 | 整数\n",
        ">FBS | (空腹時血糖 > 120 mg/dl) (1 = 真; 0 = 偽) | カテゴリー型 | 整数\n",
        ">RestECG | 安静時心電図の診断結果 (0, 1, 2) | カテゴリー型 | 整数\n",
        ">Thalach | 最大心拍数 | 数値型 | 整数\n",
        ">Exang | 運動誘発狭心症 (1 = はい; 0 = いいえ) | カテゴリー型 | 整数\n",
        ">Oldpeak | 安静時と比較した運動時のST低下 | 数値型 | 整数\n",
        ">Slope | ピーク運動STセグメントの勾配 | 数値型 | 浮動小数点数\n",
        ">CA | 蛍光透視法によって着色された主要血管の数（0−3） | 数値型 | 整数\n",
        ">Thal | 3 = 正常; 6 = 固定欠陥; 7 = 可逆的欠陥 | カテゴリー型 | 文字列\n",
        ">Target | 心臓疾患の診断 (1 = 真; 0 = 偽) | 分類 | 整数"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "VxyBFc_kKazA"
      },
      "source": [
        "## TensorFlow他ライブラリのインポート"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "LuOWVJBz8a6G",
        "colab": {}
      },
      "source": [
        "!pip install sklearn"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "9dEreb4QKizj",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "\n",
        "try:\n",
        "  # Colab only\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "    pass\n",
        "import tensorflow as tf\n",
        "\n",
        "from tensorflow import feature_column\n",
        "from tensorflow.keras import layers\n",
        "from sklearn.model_selection import train_test_split"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "KCEhSZcULZ9n"
      },
      "source": [
        "## Pandasを使ったデータフレーム作成\n",
        "\n",
        "[Pandas](https://pandas.pydata.org/)は、構造化データの読み込みや操作のための便利なユーティリティを持つPythonのライブラリです。ここでは、Pandasを使ってURLからデータをダウンロードし、データフレームに読み込みます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "REZ57BXCLdfG",
        "colab": {}
      },
      "source": [
        "URL = 'https://storage.googleapis.com/applied-dl/heart.csv'\n",
        "dataframe = pd.read_csv(URL)\n",
        "dataframe.head()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "u0zhLtQqMPem"
      },
      "source": [
        "## データフレームを、訓練用、検証用、テスト用に分割\n",
        "\n",
        "ダウンロードしたデータセットは1つのCSVファイルです。これを、訓練用、検証用、テスト用のデータセットに分割します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "YEOpw7LhMYsI",
        "colab": {}
      },
      "source": [
        "train, test = train_test_split(dataframe, test_size=0.2)\n",
        "train, val = train_test_split(train, test_size=0.2)\n",
        "print(len(train), 'train examples')\n",
        "print(len(val), 'validation examples')\n",
        "print(len(test), 'test examples')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "84ef46LXMfvu"
      },
      "source": [
        "## tf.dataを使った入力パイプラインの構築\n",
        "\n",
        "次に、[tf.data](https://www.tensorflow.org/guide/datasets)を使ってデータフレームをラップします。こうすることで、feature columns をPandasデータフレームの列をモデル訓練用の特徴量へのマッピングするための橋渡し役として使うことができます。（メモリに収まらないぐらいの）非常に大きなCSVファイルを扱う場合には、tf.dataを使ってディスクから直接CSVファイルを読み込むことになります。この方法は、このチュートリアルでは扱いません。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "NkcaMYP-MsRe",
        "colab": {}
      },
      "source": [
        "# Pandasデータフレームからtf.dataデータセットを作るためのユーティリティメソッド\n",
        "def df_to_dataset(dataframe, shuffle=True, batch_size=32):\n",
        "  dataframe = dataframe.copy()\n",
        "  labels = dataframe.pop('target')\n",
        "  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))\n",
        "  if shuffle:\n",
        "    ds = ds.shuffle(buffer_size=len(dataframe))\n",
        "  ds = ds.batch(batch_size)\n",
        "  return ds"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "CXbbXkJvMy34",
        "colab": {}
      },
      "source": [
        "batch_size = 5 # デモ用として小さなバッチサイズを使用\n",
        "train_ds = df_to_dataset(train, batch_size=batch_size)\n",
        "val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)\n",
        "test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "qRLGSMDzM-dl"
      },
      "source": [
        "## 入力パイプラインを理解する\n",
        "\n",
        "入力パイプラインを構築したので、それが返すデータのフォーマットを見るために呼び出してみましょう。出力を読みやすくするためにバッチサイズを小さくしてあります。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "CSBo3dUVNFc9",
        "colab": {}
      },
      "source": [
        "for feature_batch, label_batch in train_ds.take(1):\n",
        "  print('Every feature:', list(feature_batch.keys()))\n",
        "  print('A batch of ages:', feature_batch['age'])\n",
        "  print('A batch of targets:', label_batch )"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "OT5N6Se-NQsC"
      },
      "source": [
        "データセットが（データフレームにある）列名からなるディクショナリを返すことがわかります。列名から、データフレームの行に含まれる列の値が得られます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ttIvgLRaNoOQ"
      },
      "source": [
        "## feature columnsの様々な型の例\n",
        "\n",
        "TensorFlowにはたくさんの型のfeature columnがあります。このセクションでは、いくつかの型のfeature columnsを作り、データフレームの列をどのように変換しているかを示します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "mxwiHFHuNhmf",
        "colab": {}
      },
      "source": [
        "# いくつかの型のfeature columnsを例示するためこのバッチを使用する\n",
        "example_batch = next(iter(train_ds))[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0wfLB8Q3N3UH",
        "colab": {}
      },
      "source": [
        "# feature columnsを作りデータのバッチを変換する\n",
        "# ユーティリティメソッド\n",
        "def demo(feature_column):\n",
        "  feature_layer = layers.DenseFeatures(feature_column)\n",
        "  print(feature_layer(example_batch).numpy())"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Q7OEKe82N-Qb"
      },
      "source": [
        "### 数値コラム\n",
        "\n",
        "feature columnsの出力はモデルへの入力になります（上記で定義したdemo関数を使うと、データフレームの列がどのように変換されるかをつぶさに見ることができます）。[数値コラム](https://www.tensorflow.org/api_docs/python/tf/feature_column/numeric_column)は、最も単純な型のコラムです。数値コラムは実数特徴量を表現するのに使われます。このコラムを使う場合、モデルにはデータフレームの列の値がそのまま渡されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "QZTZ0HnHOCxC",
        "colab": {}
      },
      "source": [
        "age = feature_column.numeric_column(\"age\")\n",
        "demo(age)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7a6ddSyzOKpq"
      },
      "source": [
        "心臓疾患データセットでは、データフレームのほとんどの列が数値型です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "IcSxUoYgOlA1"
      },
      "source": [
        "### バケット化コラム\n",
        "\n",
        "数値をそのままモデルに入力するのではなく、値の範囲に基づいた異なるカテゴリーに分割したいことがあります。例えば、人の年齢を表す生データを考えてみましょう。[バケット化コラム](https://www.tensorflow.org/api_docs/python/tf/feature_column/bucketized_column)を使うと年齢を数値コラムとして表現するのではなく、年齢をいくつかのバケットに分割できます。下記のワンホット値が、各行がどの年齢範囲にあるかを表していることに注目してください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "wJ4Wt3SAOpTQ",
        "colab": {}
      },
      "source": [
        "age_buckets = feature_column.bucketized_column(age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])\n",
        "demo(age_buckets)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "r1tArzewPb-b"
      },
      "source": [
        "### カテゴリー型コラム\n",
        "\n",
        "このデータセットでは、Thalは（'fixed'、'normal'、'reversible'のような）文字列として表現されています。文字列を直接モデルに入力することはできません。まず、文字列を数値にマッピングする必要があります。categorical vocabulary コラムを使うと、（上記で示した年齢バケットのように）文字列をワンホットベクトルとして表現することができます。カテゴリーを表す語彙(vocabulary)は[categorical_column_with_vocabulary_list](https://www.tensorflow.org/api_docs/python/tf/feature_column/categorical_column_with_vocabulary_list)を使ってリストで渡すか、[categorical_column_with_vocabulary_file](https://www.tensorflow.org/api_docs/python/tf/feature_column/categorical_column_with_vocabulary_file)を使ってファイルから読み込むことができます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "DJ6QnSHkPtOC",
        "colab": {}
      },
      "source": [
        "thal = feature_column.categorical_column_with_vocabulary_list(\n",
        "      'thal', ['fixed', 'normal', 'reversible'])\n",
        "\n",
        "thal_one_hot = feature_column.indicator_column(thal)\n",
        "demo(thal_one_hot)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dxQloQ9jOoXL"
      },
      "source": [
        "より複雑なデータセットでは、たくさんの列がカテゴリー型（例えば文字列）であることでしょう。feature columns はカテゴリー型データを扱う際に最も役に立ちます。このデータセットでは、カテゴリー型コラムは1つだけですが、他のデータセットを扱う際に使用できるいくつかの重要な型のfeature columnsを紹介するために、この列を使用することにします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "LEFPjUr6QmwS"
      },
      "source": [
        "### 埋め込み型コラム\n",
        "\n",
        "数種類の候補となる文字列ではなく、カテゴリー毎に数千（あるいはそれ以上）の値があるとしましょう。カテゴリーの数が多くなってくると、様々な理由から、ワンホットエンコーディングを使ってニューラルネットワークを訓練することが難しくなります。埋込み型コラムを使うと、こうした制約を克服することが可能です。[埋込み型コラム](https://www.tensorflow.org/api_docs/python/tf/feature_column/embedding_column)は、データを多次元のワンホットベクトルとして表すのではなく、セルの値が0か1かだけではなく、どんな数値でもとれるような密な低次元ベクトルとして表現します。埋め込みのサイズ（下記の例では8）は、チューニングが必要なパラメータです。\n",
        "\n",
        "キーポイント：カテゴリー型コラムがたくさんの選択肢を持つ場合、埋め込み型コラムを使用することが最善の方法です。ここでは例を一つ示しますので、今後様々なデータセットを扱う際には、この例を参考にしてください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "hSlohmr2Q_UU",
        "colab": {}
      },
      "source": [
        "# この埋込み型コラムの入力は、先程作成したカテゴリ型コラムであることに注意\n",
        "thal_embedding = feature_column.embedding_column(thal, dimension=8)\n",
        "demo(thal_embedding)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "urFCAvTVRMpB"
      },
      "source": [
        "### ハッシュ化特徴コラム\n",
        "\n",
        "値の種類が多いカテゴリー型コラムを表現するもう一つの方法が、[categorical_column_with_hash_bucket](https://www.tensorflow.org/api_docs/python/tf/feature_column/categorical_column_with_hash_bucket)を使う方法です。このfeature columnは文字列をエンコードするために入力のハッシュ値を計算し、`hash_bucket_size`個のバケットの中から1つを選択します。このコラムを使用する場合には、語彙を用意する必要はありません。また、スペースの節約のために、実際のカテゴリー数に比べて極めて少ないバケット数を選択することも可能です。\n",
        "\n",
        "キーポイント：この手法の重要な欠点の一つは、異なる文字列が同じバケットにマッピングされるというハッシュ値の衝突が起きることです。実務上は、データセットによっては、この問題を無視できることがあります。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "YHU_Aj2nRRDC",
        "colab": {}
      },
      "source": [
        "thal_hashed = feature_column.categorical_column_with_hash_bucket(\n",
        "      'thal', hash_bucket_size=1000)\n",
        "demo(feature_column.indicator_column(thal_hashed))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fB94M27DRXtZ"
      },
      "source": [
        "### クロスフィーチャーコラム\n",
        "\n",
        "複数の特徴量をまとめて1つの特徴量にする、[フィーチャークロス](https://developers.google.com/machine-learning/glossary/#feature_cross)として知られている手法は、モデルが特徴量の組み合わせの一つ一つに別々の重みを学習することを可能にします。ここでは年齢とThalをクロスさせて新しい特徴量を作ってみます。交差列(`crossed_column`)が、起こりうるすべての組み合わせ全体のテーブル（これは非常に大きくなる可能性があります）を作るものではないことに注意してください。クロスフィーチャーコラムは、代わりにバックエンドとしてハッシュ化コラムを使用しているため、テーブルの大きさを選択することができます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "oaPVERd9Rep6",
        "colab": {}
      },
      "source": [
        "crossed_feature = feature_column.crossed_column([age_buckets, thal], hash_bucket_size=1000)\n",
        "demo(feature_column.indicator_column(crossed_feature))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ypkI9zx6Rj1q"
      },
      "source": [
        "## 使用するコラムを選択する\n",
        "\n",
        "これまで、いくつかのfeature columnの使い方を見てきました。いよいよモデルの訓練にそれらを使用することにします。このチュートリアルの目的は、feature columnsを使うのに必要な完全なコード（いわば力学）を示すことです。以下ではモデルを訓練するための列を適当に選びました。\n",
        "\n",
        "キーポイント：正確なモデルを構築するのが目的である場合には、できるだけ大きなデータセットを使用して、どの特徴量を含めるのがもっとも意味があるのかや、それらをどう表現したらよいかを、慎重に検討してください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "4PlLY7fORuzA",
        "colab": {}
      },
      "source": [
        "feature_columns = []\n",
        "\n",
        "# 数値コラム\n",
        "for header in ['age', 'trestbps', 'chol', 'thalach', 'oldpeak', 'slope', 'ca']:\n",
        "  feature_columns.append(feature_column.numeric_column(header))\n",
        "\n",
        "# バケット化コラム\n",
        "age_buckets = feature_column.bucketized_column(age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])\n",
        "feature_columns.append(age_buckets)\n",
        "\n",
        "# インジケーター（カテゴリー型）コラム\n",
        "thal = feature_column.categorical_column_with_vocabulary_list(\n",
        "      'thal', ['fixed', 'normal', 'reversible'])\n",
        "thal_one_hot = feature_column.indicator_column(thal)\n",
        "feature_columns.append(thal_one_hot)\n",
        "\n",
        "# 埋め込み型コラム\n",
        "thal_embedding = feature_column.embedding_column(thal, dimension=8)\n",
        "feature_columns.append(thal_embedding)\n",
        "\n",
        "# クロスフィーチャーコラム\n",
        "crossed_feature = feature_column.crossed_column([age_buckets, thal], hash_bucket_size=1000)\n",
        "crossed_feature = feature_column.indicator_column(crossed_feature)\n",
        "feature_columns.append(crossed_feature)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "M-nDp8krS_ts"
      },
      "source": [
        "### 特徴量層の構築\n",
        "\n",
        "feature columnsを定義し終わったので、次に[DenseFeatures](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/layers/DenseFeatures)層を使ってKerasモデルへの入力とします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "6o-El1R2TGQP",
        "colab": {}
      },
      "source": [
        "feature_layer = tf.keras.layers.DenseFeatures(feature_columns)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8cf6vKfgTH0U"
      },
      "source": [
        "これまでは、feature columnsの働きを見るため、小さなバッチサイズを使ってきました。ここではもう少し大きなバッチサイズの新しい入力パイプラインを作ります。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gcemszoGSse_",
        "colab": {}
      },
      "source": [
        "batch_size = 32\n",
        "train_ds = df_to_dataset(train, batch_size=batch_size)\n",
        "val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)\n",
        "test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bBx4Xu0eTXWq"
      },
      "source": [
        "## モデルの構築、コンパイルと訓練"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "_YJPPb3xTPeZ",
        "colab": {}
      },
      "source": [
        "model = tf.keras.Sequential([\n",
        "  feature_layer,\n",
        "  layers.Dense(128, activation='relu'),\n",
        "  layers.Dense(128, activation='relu'),\n",
        "  layers.Dense(1, activation='sigmoid')\n",
        "])\n",
        "\n",
        "model.compile(optimizer='adam',\n",
        "              loss='binary_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "model.fit(train_ds, \n",
        "          validation_data=val_ds, \n",
        "          epochs=5)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "GnFmMOW0Tcaa",
        "colab": {}
      },
      "source": [
        "loss, accuracy = model.evaluate(test_ds)\n",
        "print(\"Accuracy\", accuracy)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3bdfbq20V6zu"
      },
      "source": [
        "キーポイント：一般的に、ディープラーニングが最良の結果となるのは、もっと大きくて、もっと複雑なデータセットです。この例のように小さなデータセットを使用する際には、強固なベースラインとして、決定木やランダムフォレストを使うことをおすすめします。このチュートリアルの目的は、訓練により正確なモデルを得ることではなく、構造化データの使い方をデモすることです。今後ご自分のデータセットに取り組まれる際の出発点として、これらのコードをお使いください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SotnhVWuHQCw"
      },
      "source": [
        "## 次のステップ\n",
        "\n",
        "構造化データの分類について更に多くのことを学ぶためには、自分自身で試してみることです。別のデータセットを見つけ、上記と同様のコードを使って、それを分類するモデルを訓練してみてください。正解率を上げるためには、モデルにどの特徴量を含めたらよいかや、その特徴量をどのように表現すべきかをじっくり考えてください。"
      ]
    }
  ]
}
